#include "stdafx.h"

#include "common.h"

#include "..\..\includes\mfciterators.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTests
{
	TEST_CLASS(Map_UnitTests)
	{
	public:
		
		TEST_METHOD(Test_Map_int_int)
		{
			CMap<int, int, int, int> map;

         for(auto v : g_sample)
            map.SetAt(v, v+10);

         TraceTestMap(map, "%d-%d");
         TraceTestConstMap(map, "%d-%d");

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample, p.key));
            Assert::AreEqual(p.key, p.value - 10);
         }

         for(auto & p : map)
         {
            p.value -= 10;
         }

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample, p.key));
            Assert::AreEqual(p.key, p.value);
         }
		}

      TEST_METHOD(Test_Map_int_CString)
		{
			CMap<int, int, CString, CString> map;

         for(size_t i = 0; i < g_sample.size(); ++i)
            map.SetAt(g_sample[i], g_sample_str[i]);

         TraceTestMap(map, "%d-%s");
         TraceTestConstMap(map, "%d-%s");

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample, p.key));
            Assert::IsTrue(contains(g_sample_str, p.value));
         }

         for(auto & p : map)
         {
            p.value.MakeUpper();
         }

         TraceTestMap(map, "%d-%s");
         TraceTestConstMap(map, "%d-%s");

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample, p.key));
            Assert::IsTrue(contains(g_sample2_str, p.value));
         }
		}

      TEST_METHOD(Test_Map_CString_int)
		{
			CMap<CString, LPCTSTR, int, int> map;

         for(size_t i = 0; i < g_sample.size(); ++i)
            map.SetAt(g_sample_str[i], g_sample[i]);

         TraceTestMap(map, "%s-%d");
         TraceTestConstMap(map, "%s-%d");

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample_str, p.key));
            Assert::IsTrue(contains(g_sample, p.value));
         }

         for(auto & p : map)
         {
            p.value += 10;
         }

         TraceTestMap(map, "%s-%d");
         TraceTestConstMap(map, "%s-%d");

         for(auto const & p : map)
         {
            Assert::IsTrue(contains(g_sample_str, p.key));
            Assert::IsTrue(contains(g_sample, p.value - 10));
         }
		}

      TEST_METHOD(Test_CTypedPtrMap_CMapPtrToPtr)
      {
         CTypedPtrMap<CMapPtrToPtr, CBar*, CBar*> map;

         for(auto v : g_sample)
         {
            map.SetAt(new CBar(v), new CBar(v*2));
         }

         TraceTestMap(map, "%p-%p");
         TraceTestConstMap(map, "%p-%p");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         auto const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key->value*2, kvp.value->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.key;
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CTypedPtrMap_CMapPtrToWord)
      {
         CTypedPtrMap<CMapPtrToWord, CBar*, WORD> map;

         for(auto v : g_sample)
         {
            map.SetAt(new CBar(v), v);
         }

         TraceTestMap(map, "%p-%u");
         TraceTestConstMap(map, "%p-%u");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         auto const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, kvp.key->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.key;
         }
      }

      TEST_METHOD(Test_CTypedPtrMap_CMapWordToPtr)
      {
         CTypedPtrMap<CMapWordToPtr, WORD, CBar*> map;

         for(auto v : g_sample)
         {
            map.SetAt(v, new CBar(v));
         }

         TraceTestMap(map, "%u-%p");
         TraceTestConstMap(map, "%u-%p");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         auto const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, kvp.value->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CTypedPtrMap_CMapStringToPtr)
      {
         CTypedPtrMap<CMapStringToPtr, CString, CBar*> map;

         auto i = 0;
         for(auto v : g_sample_str)
         {
            map.SetAt(v, new CBar(g_sample[i++]));
         }

         TraceTestMap(map, "%s-%p");
         TraceTestConstMap(map, "%s-%p");

         for(auto kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value));
         }

         for(auto & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value));

            (static_cast<CBar*>(kvp.value))->value++;
         }

         for(auto const & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         auto const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto const & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CMapPtrToWord)
      {
         CMapPtrToWord map;

         for(auto v : g_sample)
         {
            map.SetAt(new CBar(v), v);
         }

         TraceTestMap(map, "%p-%u");
         TraceTestConstMap(map, "%p-%u");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         CMapPtrToWord const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.value, (static_cast<CBar*>(kvp.key))->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.key;
         }
      }

      TEST_METHOD(Test_CMapPtrToPtr)
      {
         CMapPtrToPtr map;

         for(auto v : g_sample)
         {
            map.SetAt(new CBar(v), new CBar(v*2));
         }

         TraceTestMap(map, "%p-%p");
         TraceTestConstMap(map, "%p-%p");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value*2, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value * 2, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value * 2, (static_cast<CBar*>(kvp.value))->value);
         }

         CMapPtrToPtr const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value * 2, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value * 2, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>((static_cast<CBar*>(kvp.key))->value * 2, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.key;
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CMapStringToOb)
      {
         CMapStringToOb map;

         auto i = 0;
         for(auto v : g_sample_str)
         {
            map.SetAt(v, new CFooObject(g_sample[i++]));
         }

         TraceTestMap(map, "%s-%p");
         TraceTestConstMap(map, "%s-%p");

         for(auto kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value));
         }

         for(auto & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value));

            (static_cast<CFooObject*>(kvp.value))->value++;
         }

         for(auto const & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value-1));
         }

         CMapStringToOb const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value-1));
         }

         for(auto & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value-1));
         }

         for(auto const & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CFooObject*>(kvp.value))->value-1));
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CMapStringToPtr)
      {
         CMapStringToPtr map;

         auto i = 0;
         for(auto v : g_sample_str)
         {
            map.SetAt(v, new CBar(g_sample[i++]));
         }

         TraceTestMap(map, "%s-%p");
         TraceTestConstMap(map, "%s-%p");

         for(auto kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value));
         }

         for(auto & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value));

            (static_cast<CBar*>(kvp.value))->value++;
         }

         for(auto const & kvp : map)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         CMapStringToPtr const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto const & kvp : cmap)
         {
            Assert::IsTrue(contains(g_sample_str, kvp.key));
            Assert::IsTrue(contains(g_sample, (static_cast<CBar*>(kvp.value))->value-1));
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CMapStringToString)
      {
         CMapStringToString map;

         auto i = 0;
         for(auto v : g_sample_str)
         {
            map.SetAt(v, g_sample2_str[i++]);
         }

         TraceTestMap(map, "%s-%s");
         TraceTestConstMap(map, "%s-%s");

         for(auto kvp : map)
         {
            Assert::AreEqual(kvp.key, kvp.value.MakeLower());
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual(kvp.key, kvp.value.MakeLower());
         }

         for(auto const & kvp : map)
         {
            auto temp = kvp.value;
            Assert::AreEqual(kvp.key, temp.MakeLower());
         }

         CMapStringToString const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual(kvp.key, kvp.value.MakeLower());
         }

         for(auto & kvp : cmap)
         {
            auto temp = kvp.value;
            Assert::AreEqual(kvp.key, temp.MakeLower());
         }

         for(auto const & kvp : cmap)
         {
            auto temp = kvp.value;
            Assert::AreEqual(kvp.key, temp.MakeLower());
         }

      }

      TEST_METHOD(Test_CMapWordToOb)
      {
         CMapWordToOb map;

         for(auto v : g_sample)
         {
            map.SetAt(v, new CFooObject(v));
         }

         TraceTestMap(map, "%u-%p");
         TraceTestConstMap(map, "%u-%p");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         CMapWordToOb const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CFooObject*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

      TEST_METHOD(Test_CMapWordToPtr)
      {
         CMapWordToPtr map;

         for(auto v : g_sample)
         {
            map.SetAt(v, new CBar(v));
         }

         TraceTestMap(map, "%u-%p");
         TraceTestConstMap(map, "%u-%p");

         for(auto kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto const & kvp : map)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         CMapWordToPtr const & cmap = map;

         for(auto kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto const & kvp : cmap)
         {
            Assert::AreEqual<WORD>(kvp.key, (static_cast<CBar*>(kvp.value))->value);
         }

         for(auto & kvp : map)
         {
            delete kvp.value;
         }
      }

	};
}